﻿//Mr.ItemRemover2 - Created by CodenameGamma - 1-31-11 - For WoW Version 4.0.3
//www.honorbuddy.de
//this is a free plugin, and should not be sold, or repackaged.
//Donations Accepted. 
//Version 1.2


using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System;
using Styx.Helpers;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System.IO;
using System.Xml.Linq;
using Styx.Plugins;
using Styx;
using Styx.CommonBot;
using Styx.Common.Helpers;
using Styx.CommonBot.POI;
using Styx.CommonBot.Profiles;
using Styx.CommonBot.Database;
using Styx.Common;
using Styx.CommonBot.Frames;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;



namespace DataMiner
{

    public partial class DataMiner : HBPlugin
    {
        //Normal Stuff.
        public override string Name { get { return "DataMiner"; } }
        public override string Author { get { return "WinZ"; } }
        public override Version Version { get { return new Version(1, 0, 0); } }
        public override bool WantButton { get { return true; } }
        public override string ButtonText { get { return "DataMiner"; } }


        public override void OnButtonPress()
        {
            new FormSettings().ShowDialog();
        }

        private Dictionary<string, string> data ;
        private Dictionary<string, int> loots;
        private DateTime _lastChange;

        
        public static void debug(string format, params object[] args)
        {
            if (DataMinerSettings.Instance.debug)
                Logging.Write("[DataMiner]:" + format, args);
        }

        public static void slog(string format, params object[] args)
        { Logging.Write("[DataMiner]:" + format, args); 
        }
        private static LocalPlayer Me { get { return StyxWoW.Me; } }

        //My Crappy Initalise.
        public override void Initialize()
        {

            Styx.CommonBot.TreeRoot.OnStatusTextChanged += onStatusChanged;

            Chat.Say += Chat_Say;
            Chat.Yell += Chat_Yell;
            Chat.Whisper += Chat_Whisper;
            Chat.Party += Chat_Party;
            Chat.PartyLeader += Chat_Party;
            Chat.Guild += Chat_Guild;
            Chat.Emote += Chat_Emote;
            Chat.Battleground += Chat_BG;
            Chat.BattlegroundLeader += Chat_BG;
            Chat.Raid += Chat_Raid;
            Chat.RaidLeader += Chat_Raid;
            Lua.Events.AttachEvent("CHAT_MSG_BN_WHISPER", BNetWhisper);
            Lua.Events.AttachEvent("GMRESPONSE_RECEIVED", GMResponse);

            Styx.CommonBot.BotEvents.Player.OnMobKilled += reinitStuckTimer;
            //Lua.Events.AttachEvent("CHAT_MSG_MONEY", reinitStuckTimer);
            Lua.Events.AttachEvent("CHAT_MSG_LOOT", onLoot);
            
            Styx.CommonBot.BotEvents.OnBotStopped += onStop;
            Styx.CommonBot.BotEvents.OnBotStarted += onStart;


            //StuckTimer.Finished += onStuckTimerFinshed;


            data = new Dictionary<string, string>();
            data.Add("name", "");
            data.Add("server", "");
            data.Add("gold", "");
            data.Add("sessionId", "");
            data.Add("nodes", "");
            data.Add("goal", "");
            data.Add("status", "");
            loots = new Dictionary<string, int>();
            DataMinerSettings.Instance.Load();
            CheckTimer.Reset(); //should start the timer
            StuckTimer.Reset();
            _lastChange = new DateTime();
            slog("Initialzed");
        }

        public override void Dispose()
        {
            
            Chat.Say -= Chat_Say;
            Chat.Yell -= Chat_Yell;
            Chat.Whisper -= Chat_Whisper;
            Chat.Party -= Chat_Party;
            Chat.PartyLeader -= Chat_Party;
            Chat.Guild -= Chat_Guild;
            Chat.Emote -= Chat_Emote;
            Chat.Battleground -= Chat_BG;
            Chat.BattlegroundLeader -= Chat_BG;
            Chat.Raid -= Chat_Raid;
            Chat.RaidLeader -= Chat_Raid;
            Lua.Events.DetachEvent("CHAT_MSG_BN_WHISPER", BNetWhisper);
            Lua.Events.DetachEvent("GMRESPONSE_RECEIVED", GMResponse);

            Styx.CommonBot.BotEvents.Player.OnMobKilled -= reinitStuckTimer;
            Lua.Events.DetachEvent("CHAT_MSG_MONEY", reinitStuckTimer);
            Lua.Events.DetachEvent("CHAT_MSG_LOOT", onLoot);
            

            Styx.CommonBot.BotEvents.OnBotStopped -= onStop;
            StuckTimer.Finished += new WaitTimerFinishedHandler(onStuckTimerFinshed);
            Styx.CommonBot.BotEvents.OnBotStarted -= onStart;
            Styx.CommonBot.TreeRoot.OnStatusTextChanged -= onStatusChanged;

            StuckTimer.Finished -= onStuckTimerFinshed;
            
            DataMinerSettings.Instance.Load();
            CheckTimer.Reset(); //should start the timer
        }
        

        public bool init;
        //Stopwatch CheckTimer = new Stopwatch();
        public static int delay = DataMinerSettings.Instance.Time;
        public WaitTimer CheckTimer = new WaitTimer(TimeSpan.FromSeconds(DataMinerSettings.Instance.Time));
        public WaitTimer StuckTimer = new WaitTimer(TimeSpan.FromSeconds(DataMinerSettings.Instance.StuckTime));
        

        public bool EnableCheck = true;
        private int _lastNodes;
        private int _newNodes;
        private uint _lastExperience = 0;

   
        public override void Pulse()
        {
            if (Me.Experience != _lastExperience)
            {
                _lastExperience = Me.Experience;
                reinitStuckTimer(new EventArgs());
            };

            if (CheckTimer.TimeLeft.Seconds <= 0)
            {
                GetData();
                send(data);

                /*
                if (lootOn && loots.Count > 0)
                    {
                        var newDict = new Dictionary<string, string>();
                        debug("Loots ---");
                        foreach (var kv in loots) {
                            newDict.Add(kv.Key, kv.Value.ToString());
                            debug("   {0} => {1}", kv.Key, kv.Value.ToString());
                        }
                        newDict.Add("sessionId", data["sessionId"]);
                        send(newDict,"Loots");
                    }
                */
                CheckTimer.Reset();

            }
            //slog("Stuck timer : {0} ({1})", StuckTimer.IsFinished, StuckTimer.TimeLeft);

            if (StuckTimer.IsFinished)
            {

                List<WoWUnit> objList = ObjectManager.GetObjectsOfType<WoWUnit>()
                    .Where(ob => (ob.IsTargetingMeOrPet)).OrderBy(ob => ob.Distance).ToList();
                if (objList.Count == 0 && Me.Combat)
                {
                    antiCombatBug();
                }
                StuckTimer.Reset();
            }
        }




        private void onStuckTimerFinshed(object sender, WaitTimer.WaitTimerEventArgs args)
        {
            if ((BotManager.Current.Name == "Gatherbuddy2"))
            {
                slog("No loot, no experience, and no mob killed for the StuckTime delay. Executing the antistuck routine");
                if (Me.Combat && !Me.IsActuallyInCombat && BotManager.Current.Name == "Gatherbuddy2")
                    antiCombatBug();
            }
        }

        private void onStatusChanged(object sender, Styx.CommonBot.StatusTextChangedEventArgs args)
        {
            data["status"] = args.NewStatus;
            _lastChange = new DateTime();
            //StuckTimer.Reset();
        }
        


        private void onStart(EventArgs args)
        {
            Styx.CommonBot.TreeRoot.OnStatusTextChanged += onStatusChanged;
            _newNodes = 0;
            _lastNodes = 0;
            data["sessionId"] = "";
            data["status"] = "";
           _lastChange = new DateTime();
        }

        private void onStop(EventArgs args)
        {
        }

        private bool lootOn = true;
        private void onLoot(object sender, LuaEventArgs args)
        {
            if (BotManager.Current.Name != "Gatherbuddy2")
                return;
            //StuckTimer.Reset();
            // Dirty hack to fix the double trigger pb
            if (!lootOn)
            {
                lootOn = true;
                return;
            }
            else lootOn = false;

            string s = args.Args[0].ToString(); 
            string id = s.Split('|')[2].Split(':')[1];
            
            string q = "";
            Match m = Regex.Match(s.Split('|')[5], @"x([\d]*)\.");
            if (m.Success)
                q = m.Groups[1].Value;
            else q = "1";

            int qInt = int.Parse(q);
            //debug("Looted ID:<{0}> q:<{1}> msg : {2}", id, qInt, args.Args[0]);
            

            try
            {
                loots[id] += int.Parse(q);
            }
            catch (KeyNotFoundException)
            {
                loots[id] = int.Parse(q);
            }
            debug("loots:[{0}]={1}", id, loots[id]);
            
            //data["test"] = "data";
        }

#region chat

        private bool chatOn;
        private void Chatter(string message, string author = "", string type = "")
        {
            if (chatOn)
                chatOn = false;
            else
            {
                chatOn = true;
                return;
            }

            slog("Chat: From: {1}  Message: {0} Type: {2}", message, author, type);
            ChatMessage mess = new ChatMessage();
            mess.server = Me.RealmName.ToString();
            mess.senderName = author;
            mess.recipientName = Me.Name.ToString();
            mess.text = message;
            mess.type = type;

            Util.HttpPost("http://" + DataMinerSettings.Instance.ServerUrl + "/message", mess.toHashTable());


/*            data["chat_message"] = message;
            data["chat_type"] = type;
            data["chat_from"] = author;

            if (
                (BuddyConSettings.Instance.notfSay && type == "CHAT_MSG_SAY") ||
                (BuddyConSettings.Instance.notfGuild && type == "CHAT_MSG_GUILD") ||
                (BuddyConSettings.Instance.notfBG && (type == "CHAT_MSG_BATTLEGROUND" || type == "CHAT_MSG_BATTLEGROUND_LEADER")) ||
                (BuddyConSettings.Instance.notfRaid && (type == "CHAT_MSG_RAID" || type == "CHAT_MSG_RAID_LEADER")) ||
                (BuddyConSettings.Instance.notfWhisper && type == "CHAT_MSG_WHISPER")
                )
            {
                if (BuddyConSettings.Instance.debug) Logging.Write("[bC]: send notification");
                Util.sendToProwl("Chat", string.Format("[bC]: Chat: From: {1}  Message: {0} Type: {2}", message, author, type), data["name"], data["server"]);
                if (BuddyConSettings.Instance.androidapi.Length > 10) Util.SendNotification(BuddyConSettings.Instance.androidapi, "{\"from\":\"" + author + "\", \"message\":\"" + message + "\", \"type\":\"" + type + "\"}");
            }
            if (BuddyConSettings.Instance.scChat) screenie();
            //send(data);
*/
        }


        private void BNetWhisper(object sender, LuaEventArgs args)
        {
            debug("Chat: Bnet From: {1}  Message: {0} Type: {2}", (string)args.Args[0], args.Args[1], args.ToString());
        }

        private void GMResponse(object sender, LuaEventArgs args)
        {
            debug("Chat: GM From: {1}  Message: {0} Type: {2}", (string)args.Args[0], args.Args[1], args.ToString());
        }

        private void Chat_Raid(Styx.CommonBot.Chat.ChatLanguageSpecificEventArgs e)
        {
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);
        }

        private void Chat_BG(Styx.CommonBot.Chat.ChatLanguageSpecificEventArgs e)
        {
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Emote(Styx.CommonBot.Chat.ChatAuthoredEventArgs e)
        {

            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Party(Styx.CommonBot.Chat.ChatLanguageSpecificEventArgs e)
        {
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Whisper(Styx.CommonBot.Chat.ChatWhisperEventArgs e)
        {
            debug("Chat -> Whisper From: {1}  Message: {0} Type: {2}", (string)e.Message, e.Author, e.EventName);
            //Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            //thread.Start();
            Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Yell(Styx.CommonBot.Chat.ChatLanguageSpecificEventArgs e)
        {
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Say(Styx.CommonBot.Chat.ChatLanguageSpecificEventArgs e)
        {
            debug("Chat -> Say From: {1}  Message: {0} Type: {2}", (string)e.Message, e.Author, e.EventName);
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);        
        }

        private void Chat_Guild(Styx.CommonBot.Chat.ChatGuildEventArgs e)
        {
            Thread thread = new Thread(delegate() { Chatter(e.Message, e.Author, e.EventName); });
            thread.Start();
            //Chatter(e.Message, e.Author, e.EventName);        
        }




        private void reinitStuckTimer(object sender, LuaEventArgs args)
        {
            StuckTimer.Reset();
            if(StuckTimer.IsFinished)
                debug("StuckTimer reinitiatized");
        }


        private void reinitStuckTimer(EventArgs e)
        {
            StuckTimer.Reset();
        }


#endregion

        private void GetData()
        {
            data["name"] = Me.Name.ToString();
            data["server"] = Me.RealmName.ToString();
            data["gold"] = (Me.Copper / 10000).ToString();
            data["goal"] = (TreeRoot.GoalText == null ? "":TreeRoot.GoalText);
            data["status"] = TreeRoot.StatusText;
            
            _newNodes = 0;
            foreach(KeyValuePair<string,int> kv in Bots.Gatherbuddy.GatherbuddyBot.NodeCollectionCount)
                _newNodes += kv.Value;
            data["nodes"] = string.Format("{0}", (_newNodes - _lastNodes));
            debug("Nodes : {0}", data["nodes"]);
            debug("Goal : {0}", TreeRoot.GoalText);
            debug("Status : {0}", TreeRoot.StatusText);

        }

        private void send(Dictionary<string, string> datax)
        {
            send(datax, "Update");
        }
        
        private void send(Dictionary<string, string> datax, string func)
        {
            try
                {
 
                    string response = "";
                    string url ="http://" + DataMinerSettings.Instance.ServerUrl + "/" + func;
                    if (DataMinerSettings.Instance.debug)
                        url += "?XDEBUG_SESSION_START=netbeans-xdebug";
                    response = Util.HttpPost(url, datax);
                    
                    if (response != "")
                    {
                        debug("Response = {0}",response);
                        Hashtable resJson = (Hashtable)JSON.JsonDecode(response);
/*                        if (resJson.ContainsKey("sessionId"))
                        {
                            data["sessionId"] = resJson["sessionId"].ToString();
                        }
*/                        
                        switch ((string)resJson["response"])
                        {
                            case "":
                                break;
                            case "success":
                                debug("[DataMiner]:  {0}", "Success Updating");
                                _lastNodes = _newNodes;
                                data["sessionId"] = resJson["sessionId"].ToString();
                                break;
                            case "lootok":
                                loots = new Dictionary<string, int>();
                                break;

/*                            case "killwow":
                                Logging.Write(string.Format("[DataMiner]:  {0}", "Kill Wow requested!"));
                                Styx.StyxWoW.Memory.Process.Kill();
                                break;
                            case "screen":
                                screenie();
                                break;
                            case "chat":
                                sendChat((string)resJson["type"], (string)resJson["message"], (string)resJson["to"]);
                                break;
                            case "stophb":
                                Styx.CommonBot.TreeRoot.Stop();
                                break;
                            case "starthb":
                                Styx.CommonBot.TreeRoot.Start();
                                break;
*/                            default:
                                slog(string.Format("[DataMiner]:  No Success {0}", response));
                                break;

                        }

                    }
                }
                catch (System.InvalidCastException e)
                {
                    Logging.Write(string.Format("[DataMiner]: error cast {0}", e.Message));
                }
                catch (Exception e)
                {
                    Logging.Write(string.Format("[DataMiner]: error send {0}", e.Message));
                }
            }




        void antiCombatBug()
        {
            if ((BotManager.Current.Name != "Gatherbuddy2"))
                return;
            if (Me.IsDead)
                return;


            slog("No Mob tagerting me found, take the closest hostile one");
            List<WoWUnit> objList = ObjectManager.GetObjectsOfType<WoWUnit>()
                .Where(ob => (ob.Attackable && ob.IsHostile && ob.Distance < 50 && ob.IsAlive)).OrderBy(ob => ob.Distance).ToList();
            WoWUnit o = objList.FirstOrDefault();

            slog("{0} units in list", objList.Count);

            if (o == null)
            {
                slog("No mobs found");
                return;
            }

            
            /*
            foreach (WoWUnit ob in objList)
            {
                slog("anitiStuck :  {0} Targetting me = {1}",ob.Name, ob.IsTargetingMeOrPet);
            }
            */
            slog("anitiStuck :   {0} selected",o.Name);
            
            if (o != null && o.IsAlive)
            {
                o.Target();
                while (o.Distance > 5)
                {
                    Styx.Pathing.Navigator.MoveTo(o.Location);
                    Thread.Sleep(100);
                }
                o.Interact();
                Styx.CommonBot.Routines.RoutineManager.Current.Pull();
            }
                        
            slog("anitiStuck :   DONE");
            
        }

    }

}

